using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace ProjectCastamere
{
    abstract class Menu : GameState
    {
        private Texture2D background;

        private SpriteBatch spriteBatch;
        private List<String> options = new List<String>();
        private List<bool> transitionOut = new List<bool>();

        /// <summary>
        /// when the user selects an option the entire screen should slide to the right
        /// as a transitional animation, this keeps track of that
        /// </summary>
        private float xScreenOffset = 0.0f;
        private SpriteFont font;

        private enum State
        {
            // menu is in idle state
            Idle,
            // menu is transitioning in
            TransitioningIn,
            // menu is transitioning out
            TransitioningOut,

            OutOfFrame
        }

        private State state = State.Idle;

        /// <summary>
        /// this value is the index of the first option in the top of the viewport
        /// </summary>
        private int viewOptionIndex = 0;

        /// <summary>
        /// number of options that are displayed on screen
        /// </summary>
        private const int numOptionsOnScreen = 8;

        private struct OptionHighlight
        {
            public Texture2D texture;
            public Rectangle dstRect;
        }

        private OptionHighlight[] highlights = new OptionHighlight[numOptionsOnScreen];


        private void LoadOptionHighlights()
        {
            // TODO: load from file?
            OptionHighlight h;

            for (int i = 0; i < numOptionsOnScreen; ++i)
            {
                h.texture = application.Content.Load<Texture2D>("oh" + (i + 1));
                h.dstRect = new Rectangle(60, i * 135, 500, 135);

                highlights[i] = h;
            }
        }

        /// <summary>
        /// the currently selected item on the menu
        /// </summary>
        private int currentSelection = 0;



        public Menu(Application app)
            : base(app)
        {
            spriteBatch = new SpriteBatch(application.GraphicsDevice);

            background = this.application.Content.Load<Texture2D>("MainMenu");

            font = this.application.Content.Load<SpriteFont>("MenuFont");

            LoadOptionHighlights();
        }

        public void AddOption(String option, bool transitionOutWhenSelected)
        {
            options.Add(option);
            transitionOut.Add(transitionOutWhenSelected);
        }


        public override void FocusGained()
        {
            xScreenOffset = 1920.0f;
            state = State.TransitioningIn;
        }

        public override void FocusLost()
        {
        }

        // Poll user input
        public override void Input()
        {
            // query user input
         
            // If the user presses up or down
            if (InputManager.IsActionTriggered(InputManager.GameActions.CursorDown))
            {
                MoveDown();
            }
            else if (InputManager.IsActionTriggered(InputManager.GameActions.CursorUp))
            {
                MoveUp();
            }

            // If the user presses Enter
            if (InputManager.IsActionTriggered(InputManager.GameActions.Ok))
            {
                Select();
            }
        }

        public void MoveUp()
        {
            if (state != State.Idle)
            {
                return;
            }

            currentSelection--;
            if (currentSelection < 0)
            {
                currentSelection = 0;
            }
            // Play sound
            AudioManager.Play2DSoundEffect("MenuMove");
        }

        public void MoveDown()
        {
            if (state != State.Idle)
            {
                return;
            }

            currentSelection++;
            if (currentSelection >= options.Count)
            {
                currentSelection = options.Count-1;
            }
            // Play sound
            AudioManager.Play2DSoundEffect("MenuMove");
        }

        public void Select()
        {
            // Play Sound
            AudioManager.Play2DSoundEffect("Continue");

            if (state != State.Idle && state != State.TransitioningIn)
            {
                return;
            }

            if (transitionOut[currentSelection])
            {
                state = State.TransitioningOut;
            }
            else
            {
                OptionSelected(options[currentSelection]);
            }
        }

        public override void Update()
        {
            const float Speed = 100.0f;
            switch (state)
            {
                case State.TransitioningIn:
                    {
                        xScreenOffset -= Speed;
                        if (xScreenOffset <= 0.0f)
                        {
                            xScreenOffset = 0.0f;
                            state = State.Idle;
                        }
                    }
                    break;
                case State.TransitioningOut:
                    {
                        xScreenOffset += Speed;
                        if (xScreenOffset >= 1920.0f)
                        {
                            xScreenOffset = 1920.0f;
                            OptionSelected(options[currentSelection]);
                            state = State.OutOfFrame;
                        }
                    }
                    break;
            }
        }

        private int[] xpos = { 240, 160, 120, 80, 80, 120, 160, 240 };

        public override void Draw()
        {
            spriteBatch.Begin();

            int width = application.GraphicsDevice.PresentationParameters.BackBufferWidth;
            int height = application.GraphicsDevice.PresentationParameters.BackBufferHeight;

            spriteBatch.Draw(background, new Rectangle((int)application.convertX(xScreenOffset), 0, width, height), Color.White);

            // draw the option highlight
            int index = currentSelection - viewOptionIndex;
            OptionHighlight oh = highlights[index];

            Rectangle rect = new Rectangle();
            rect.X = (int)application.convertX(oh.dstRect.X + xScreenOffset);
            rect.Y = (int)application.convertY(oh.dstRect.Y);
            rect.Width = (int)application.convertX(oh.dstRect.Width);
            rect.Height = (int)application.convertY(oh.dstRect.Height);

            float col = (index / 8.0f);

            spriteBatch.Draw(oh.texture, rect, new Color(new Vector3(col,0,1)));

            // draw all the menu options from viewOptionIndex to viewOptionIndex + numOptionsOnScreen
            int start = viewOptionIndex;
            int end = viewOptionIndex + numOptionsOnScreen;
            if (end > options.Count)
            {
                end = options.Count;
            }
            for(int i = start; i < end; ++i)
            {
                Vector2 size = font.MeasureString(options[i]);
                float ypos = (i * application.convertY(135)) +((application.convertY(135) - size.Y) / 2.0f);

                Color c = Color.Yellow;
                if (i == currentSelection)
                {
                    c = Color.Orange;
                }

                spriteBatch.DrawString(font, options[i], new Vector2(application.convertX(xpos[i] + xScreenOffset), ypos), c);
            }

            spriteBatch.End();
        }


        public abstract void OptionSelected(String option);


    }
}
